package com.liu;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;

/**
 * Created by Administrator on 2019/8/28 0028.
 */
public class NIOServer {

    // /     通道管理器
    private Selector selector;


    public void  initServer(int port) throws IOException {
//        获得一个serversocket 通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//          设置通道为非 阻塞
        serverSocketChannel.configureBlocking(false);
//         通道绑定端口
        serverSocketChannel.socket().bind(new InetSocketAddress(port));
//           通过通道获得一个通道管理器
        this.selector=Selector.open();
//        将通道管理器和该通道绑定，并未该通过到注册SelectKey.op_accept事件，注册该事件后
//        当该事件到达时，selector.select()会返回，如果该事件没有到达就会一直阻塞
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    }

    /**
     * 轮询的方式监听selector 上是否有需要处理的事件，如果有，则进行处理
     * @throws IOException
     */
    public void  listen () throws IOException {
        System.out.println("服务端启动成功！！！");
//      轮询 访问 selector
        while (true){
//            当注册事件到达时，方法返回，否则会一直阻塞。
            selector.select();
//            获得selector中选中项的迭代器，选中项为注册的事件
            Iterator its= this.selector.selectedKeys().iterator();
            while (its.hasNext()){
                SelectionKey key = (SelectionKey) its.next();
//               删除已经选的key，防治重复处理
                its.remove();
                handler(key);
            }

        }


    }

    /**
     *  处理请求
     * @param key
     */
    private void handler(SelectionKey key) throws IOException {
//        客户端请求连接事件
        if (key.isAcceptable()){
            handlerAccept(key);
        }else if (key.isReadable()){
            handlerRead(key);
        }


    }

    /**
     * 处理连接事件
     * @param key
     */
    private void handlerAccept(SelectionKey key) throws IOException {
     ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
//      通过服务 获得客户端连接的通道
     SocketChannel channel = serverChannel.accept();
//    将通道设置成非阻塞
     channel.configureBlocking(false);
     System.out.println("新的客户端连接上来。。。");
//    在和客户端连接成功之后，我们可以接到客户端的信息，需要给通道设置读的权限。
        channel.register(this.selector,SelectionKey.OP_READ);


    }

    /**
     *  处理读的事件
      * @param key
     */
    private void handlerRead(SelectionKey key) throws IOException {
//     服务器可读取的小实习得到事件发生的通道。
        SocketChannel channel = (SocketChannel) key.channel();
//     创建读取的缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int read = channel.read(buffer);
        if(read>0){
            byte [] data = buffer.array();
            String msg = new String(data, Charset.forName("GBK")).trim();
            System.out.print(Thread.currentThread().getName()+"======");
            System.out.println("服务器接收到的消息："+msg);


//       回写数据
            ByteBuffer out = ByteBuffer.wrap("ok".getBytes());
//           将消息发送给客户端
            channel.write(out);

        }else {
            System.out.println("客户端已经关闭");
            key.cancel();
        }


    }

//    启动服务端测试
    public static void main(String[] args) throws IOException {
     NIOServer server = new NIOServer();
     server.initServer(10020);
     server.listen();
    }



}
